/*
 * @(#)InterceptorTemplate.java 1.0 2009/12/01
 */
package stardust.core.java.interceptor;


import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import stardust.core.java.reflect.TypeUtils;


/**
 * 拦截器源代码模板生成类。
 * <p>
 * 生成用于拦截的源代码。
 * <p/>
 * @version 1.0, 2009/12/01
 * @author ChenChang
 */
public class InterceptorTemplate
{

  public static final Class<?> INTERCEPTORPROCESSOR = InterceptorProcessor.class;

  public static final Class<?> INTERCEPTOREXCEPTION = InterceptorException.class;

  public static final Class<?> INTERCEPTORIDENTITY = InterceptorIdentity.class;

  public static final Class<?> INTERCEPTOR = Interceptor.class;
  
  private InterceptorTemplateCallback callback;

  /**
   * 需要代理的类。
   */
  protected Class<?> source;

  /**
   * 将要产生的包名。
   */
  protected String packageName;

  /**
   * 将要产生的类名。
   */
  protected String className;

  /**
   * 产生的代码。
   */
  protected String code;

  /**
   * 创造新的拦截器模板生成对象。
   */
  public InterceptorTemplate(String packageName, String className, Class<?> source, InterceptorTemplateCallback callback)
  {
    int mod = source.getModifiers();

    if (Modifier.isAbstract(mod) || Modifier.isFinal(mod) || Modifier.isInterface(mod))
    {
      throw new InterceptorException("无法访问拥有 abstract, final, interface 访问修饰符的类:" + Modifier.toString(mod));
    }

    this.source = source;
    this.className = className;
    this.packageName = packageName;
    this.callback = callback;

    this.checkClass();

    this.code = this.privateGetCode();
  }

  /**
   * 获取产生的全限定类名。
   */
  public String getClassName()
  {
    return this.packageName + "." + this.className;
  }

  /**
   * 获取产生的源代码。
   */
  public String getCode()
  {
    return this.code;
  }

  /**
   * 检查类的可访问性。
   */
  private void checkClass()
  {
    try
    {
      Constructor<?> c = this.source.getConstructor();
      int mod = c.getModifiers();

      if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod))
      {
        throw new InterceptorException("[" + this.source.getName() + "] 类不符合 JavaBean 规范，无法创建代理类，应该让它具有一个公共的无任何参数的构造器。");
      }
    }
    catch(SecurityException e)
    {
      throw new InterceptorException(this.source.getName(), e);
    }
    catch(NoSuchMethodException e)
    {
      throw new InterceptorException("[" + this.source.getName() + "] 类不符合 JavaBean 规范，无法创建代理类，应该让它具有一个公共的无任何参数的构造器。");
    }
  }

  /**
   * 生成继承的 Java 代码。
   */
  protected String privateGetCode()
  {
    StringBuffer buffer = new StringBuffer();

    // 包名
    if (this.packageName != null && this.packageName.length() > 0)
    {
      buffer.append("package ").append(this.packageName).append(";");
    }

    // 类定义
    if (this.callback != null)
    {
      this.callback.onGenerateClass(buffer, this.source);
    }
    buffer.append("public class ").append(this.className);
    buffer.append(" extends ").append(this.source.getCanonicalName());

    buffer.append(" implements ").append(INTERCEPTORIDENTITY.getName()).append(" {");

    // 拦截目标属性
    // 拦截器
    buffer.append("private ").append(this.source.getName()).append(" object;").append("private ").append(INTERCEPTOR.getName()).append(" interceptor;").append("private java.lang.reflect.Method [] methods;").append("private boolean Initialized = true;");

    // 构造器
    buffer.append("public ").append(this.className).append("(").append(this.source.getName()).append(" object, ").append(INTERCEPTOR.getName()).append(" interceptor, java.lang.reflect.Method [] methods) throws Throwable {").append("this.object = object;this.interceptor = interceptor;this.methods = methods;this.Initialized = true;}");

    // 拦截方法
    Method[] allMethod = this.source.getMethods();

    for (int i = 0; i < allMethod.length; i++)
    {
      try
      {
        buffer.append(this.getMethodDefine(allMethod[i])).append("{").append(this.getInterceptMethod(allMethod[i])).append("}");
      }
      catch(IllegalArgumentException e)
      {
//        buffer.append("/*").append(e.toString()).append("*/");
      }
    }

    buffer.append("}");

    return buffer.toString();
  }

  /**
   * 生成拦截方法定义。
   */
  protected String getMethodDefine(Method m) throws IllegalArgumentException
  {
    StringBuffer buffer = new StringBuffer();

    // 访问修饰符
    int mod = m.getModifiers();

    if (Modifier.isNative(mod)
        || Modifier.isAbstract(mod)
        || Modifier.isPrivate(mod)
        || Modifier.isStatic(mod)
        || Modifier.isFinal(mod)
        || Modifier.isTransient(mod))
    {
      throw new IllegalArgumentException("无法访问拥有private, static, final, native, abstract, transient访问修饰符的方法：" + m.toString());
    }
    
    if (this.callback != null)
    {
      this.callback.onGenerateMethod(buffer, m);
    }
    buffer.append(Modifier.toString(mod));

    // 返回类型
    Type returnType = m.getReturnType();
    buffer.append(" ").append(returnType instanceof Class ? ((Class<?>) returnType).getCanonicalName() : returnType.toString());

    // 名称
    buffer.append(" ").append(m.getName());

    // 参数类型
    buffer.append("(");

    Type[] params = m.getParameterTypes();

    for (int i = 0; i < params.length; i++)
    {
      buffer.append(params[i] instanceof Class ? ((Class<?>) params[i]).getCanonicalName() : params[i].toString()).append(" arg").append(i);

      if (i < params.length - 1)
      {
        buffer.append(", ");
      }
    }

    buffer.append(")");

    // 抛出异常
    Type[] exceptions = m.getExceptionTypes();

    for (int i = 0; i < exceptions.length; i++)
    {
      if (i == 0)
      {
        buffer.append(" throws ");
      }

      buffer.append(exceptions[i] instanceof Class ? ((Class<?>) exceptions[i]).getCanonicalName() : exceptions[i].toString());

      if (i < exceptions.length - 1)
      {
        buffer.append(",");
      }
    }

    return buffer.toString();
  }

  /**
   * 生成拦截代码。
   * <p/>
   * @param m
   * <p/>
   * @return
   */
  protected String getInterceptMethod(Method m)
  {
    StringBuffer buffer = new StringBuffer();

    Type returnType = m.getReturnType();
    Type[] params = m.getParameterTypes();
    Type[] exceptions = m.getExceptionTypes();

    String returnTypeString = returnType instanceof Class<?> ? ((Class<?>) returnType).getCanonicalName() : returnType.toString();

    // 如果对象正在初始化将跳过拦截，直接调用原始方法（生成的代码需要插入到方法体最前面）。
    buffer.append("if (!this.Initialized) {");
    if (returnType != void.class)
    {
      buffer.append("return (");

      if (TypeUtils.getType(returnTypeString) == null)
      {
        buffer.append(returnTypeString);
      }
      else
      {
        buffer.append(TypeUtils.getType(returnTypeString).getCanonicalName());
      }
      buffer.append(")");
    }
    buffer.append("super.").append(m.getName()).append("(");
    for (int i = 0; i < params.length; i++)
    {
      buffer.append("arg").append(i);

      if (i < params.length - 1)
      {
        buffer.append(",");
      }
    }
    buffer.append(");");
    if (returnType == void.class)
    {
      buffer.append("return;");
    }
    buffer.append("}");

    // 开始方法调用
    buffer.append("try{").append("java.lang.reflect.Method method = this.object.getClass().getMethod(").append("\"").append(m.getName()).append("\"");

    for (int i = 0; i < params.length; i++)
    {
      buffer.append(",");
      buffer.append(params[i] instanceof Class ? ((Class<?>) params[i]).getCanonicalName() : params[i].toString()).append(".class");
    }

    buffer.append(");");

    // 判断拦截方法
    buffer.append("for (int i = 0; i < this.methods.length; i++) {");
    buffer.append("if (method.equals(this.methods[i])) {");

    if (returnType != void.class)
    {
      buffer.append("return (");

      if (TypeUtils.getType(returnTypeString) == null)
      {
        buffer.append(returnTypeString);
      }
      else
      {
        buffer.append(TypeUtils.getType(returnTypeString).getCanonicalName());
      }
      buffer.append(")");
    }

    buffer.append("this.interceptor.invoke(new ").append(INTERCEPTORPROCESSOR.getName()).append("(this.object, this.methods[i]");

    for (int i = 0; i < params.length; i++)
    {
      if (i == 0)
      {
        buffer.append(", ");
      }

      buffer.append("arg").append(i);

      if (i < params.length - 1)
      {
        buffer.append(", ");
      }
    }

    buffer.append("));");

    if (returnType == void.class)
    {
      buffer.append("return;");
    }

    buffer.append("}}");

    if (returnType != void.class)
    {
      buffer.append("return (");
      if (TypeUtils.getType(returnTypeString) == null)
      {
        buffer.append(returnTypeString);
      }
      else
      {
        buffer.append(TypeUtils.getType(returnTypeString).getCanonicalName());
      }
      buffer.append(")");
    }
    buffer.append("method.invoke(this.object");
    for (int i = 0; i < params.length; i++)
    {
      if (i == 0)
      {
        buffer.append(",");
      }

      buffer.append("arg").append(i);

      if (i < params.length - 1)
      {
        buffer.append(",");
      }
    }

    buffer.append(");}");

    // 抛出异常
    String exception;
    boolean flagThrowable = true;

    for (int i = 0; i < exceptions.length; i++)
    {
      exception = exceptions[i] instanceof Class ? ((Class<?>) exceptions[i]).getCanonicalName() : exceptions[i].toString();
      buffer.append("catch(");
      buffer.append(exception);
      buffer.append(" e){ throw e;}");

      if (flagThrowable && exception.equals("java.lang.Throwable"))
      {
        flagThrowable = false;
      }
    }

    if (flagThrowable)
    {
      buffer.append("catch(java.lang.Throwable e){throw new ").append(INTERCEPTOREXCEPTION.getName()).append("(e);}");
    }

    return buffer.toString();
  }

}
